-- SummonBlacksmithM
-- created by cheny3
-- 召唤兽工坊模块

module("SummonBlacksmithM", package.seeall);

local summonBlacksmithTable = {};
local summonBlacksmithBonusTable = {};

local whenLeaveDungeon = nil;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    summonBlacksmithTable = {};
    summonBlacksmithBonusTable = {};

    local summon_blacksmith_CSV = get_summon_blacksmith_CSV();
    for i = 1, #summon_blacksmith_CSV do
        local row = summon_blacksmith_CSV[i];

        summonBlacksmithTable[row.id] = row;
    end

    local summon_blacksmith_bonus_CSV = get_summon_blacksmith_bonus_CSV();
    for i = 1, #summon_blacksmith_bonus_CSV do
        local row = summon_blacksmith_bonus_CSV[i];

        summonBlacksmithBonusTable[row.id] = row;
    end
end

-- 模块初始化操作
function init()
    loadCsv();

    EventMgr.removeAll("SummonBlacksmithM");

    -- 离开迷宫事件
    EventMgr.register("SummonBlacksmithM", event.LEAVE_DUNGEON, whenLeaveDungeon);
end

-- 离开迷宫回调
whenLeaveDungeon = function()
    -- 删除召唤兽工坊字段
    ME.user.dbase:delete("summon_blacksmith");
end

-- 查询工坊
function query(id, path)
    local m = summonBlacksmithTable[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 查询工坊奖励
function queryBonus(id, path)
    local m = summonBlacksmithBonusTable[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 能否升级
function canLevelUp(pos, id)
    local grid = DungeonM.getGridByPos(pos);
    if grid.type ~= GRID_TYPE_SUMMON_BLACKSMITH or
        grid.state == GRID_STATE_DISABLE then
        trace("SummonBlacksmithM", "不是召唤兽工坊或已失效。");
        return false;
    end

    local blacksmithId = grid.blacksmith_id;
    local upgrades = query(blacksmithId, "upgrades");
    if table.indexOf(upgrades, id) < 0 then
        trace("SummonBlacksmithM", "工坊(%d)不允许升级(%d)。", blacksmithId, id);
        return false;
    end

    local blacksmithInfo = ME.user.dbase:query("summon_blacksmith", {});
    local info = queryBonus(id);
    local curLevel = blacksmithInfo[id] or 0;
    local maxLevel = info["max_level"];
    if type(maxLevel) == "number" and curLevel >= maxLevel then
        trace("SummonBlacksmithM", "升级项(%d)已经达到最大等级。", id);
        return "already_max_level";
    end

    -- 扣除项目判断
    local costList = queryBonus(id, "cost") or {};
    for _, cost in pairs(costList) do
        if type(cost) == "table" then
            if cost[1] == 1 then
                -- 消耗物品
                if ItemM.getAmount(ME.user, cost[2]) < cost[3] then
                    trace("SummonBlacksmithM", "物品%d(%d)不足。",cost[2], cost[3]);
                    return false;
                end
            elseif cost[2] == 2 then
                -- 消耗属性
                if ME.user:queryAttrib(cost[2]) < cost[3] then
                    trace("SummonBlacksmithM", "属性%s(%d)不足。", cost[2], cost[3]);
                    return false;
                end
            end
        end
    end

    return true;
end

-- 执行扣除
function levelUpCost(id)
    local costList = queryBonus(id, "cost");
    for _, cost in pairs(costList) do
        if type(cost) == "table" then
            if cost[1] == 1 then
                -- 物品
                if not ItemM.costAmount(ME.user, cost[2], cost[3]) then
                    -- 扣除失败
                    return false;
                end
            elseif cost[1] == 2 then
                -- 属性
                if ME.user.dbase:query(cost[2], 0) < cost[3] then
                    -- 不够扣除
                    return false;
                end
                ME.user:costAttrib(cost[2], cost[3]);
            end
        end
    end

    return true;
end

-- 升级
function tryLevelUp(pos, id)
    local blacksmithInfo = ME.user.dbase:query("summon_blacksmith", {});
    local info = queryBonus(id);

    if true ~= canLevelUp(pos, id) then
        -- 不允许升级
        return false;
    end

    if true ~= levelUpCost(id) then
        -- 扣除失败
        return false;
    end

    -- 等级+1
    if info["type"] == "level_up" then
        blacksmithInfo[id] = tonumber(blacksmithInfo[id]) + 1;
        ME.user.dbase:set("summon_blacksmith", blacksmithInfo);
    end

    local bonus = info["bonus"];
    if bonus["cure"] then
        -- 治疗
        tryCureSummon(id);
    elseif bonus["prop"] then
        -- 加属性，直接刷新即可
        tryRefreshSummon(id);
    end

    EventMgr.fire(event.SUMMON_BLACKSMITH_UPGRADE, {["pos"] = pos, ["id"] = id});

    return true;
end

-- 能否治疗（给界面判断用的）
function canCureSummon(id)
    if not queryBonus(id, "bonus")["cure"] then
        -- 不是治疗类的
        return true;
    end

    local gridList = {};
    for _, summonId in ipairs(queryBonus(id, "summon") or {}) do
        gridList = table.append(gridList, SummonM.findSummonsByClassId(summonId));
    end

    if #gridList <= 0 then
        -- 没有召唤兽格子
        return false;
    end

    -- 取第一个判断就好
    local summon = gridList[1].summon;
    if not summon then
        return false;
    end

    -- 当前血量小于最大血量
    return summon:queryAttrib("hp") < summon:queryAttrib("max_hp");
end

-- 治疗
function tryCureSummon(id)
    local summonId;
    local gridList = {};
    for _, summonId in ipairs(queryBonus(id, "summon") or {}) do
        gridList = table.append(gridList, SummonM.findSummonsByClassId(summonId));
    end

    if #gridList <= 0 then
        -- 没有召唤兽格子
        return false;
    end

    -- 治疗信息
    local cureInfo = queryBonus(id, "bonus")["cure"];

    local grid;
    for _, grid in pairs(gridList) do
        repeat
            local summon = grid.summon;

            if not summon then
                -- 没有召唤兽
                break;
            end

            if summon:isDead() then
                -- 召唤兽死亡了
                break;
            end

            -- 治疗
            if cureInfo[1] == 1 then
                -- 按百分比治疗
                local force = cureInfo[2];
                local maxHp = summon:queryAttrib("max_hp");
                local curHp = summon:queryAttrib("hp");
                -- 不能超过上限
                local value = math.min(FormulaM.invoke("CALC_BIG_DIVISION", maxHp, force, 100), maxHp - curHp);
                if value > 0 then
                    summon:addAttrib("hp", value);
                end
            end
        until true
    end

    return true;
end

-- 尝试刷新召唤兽信息
function tryRefreshSummon(id)
    local summonId;
    local gridList = {};
    for _, summonId in ipairs(queryBonus(id, "summon") or {}) do
        gridList = table.append(gridList, SummonM.findSummonsByClassId(summonId));
    end

    if #gridList <= 0 then
        -- 没有召唤兽格子
        return false;
    end

    -- 治疗信息
    local cureInfo = queryBonus(id, "bonus")["cure"];

    local grid;
    for _, grid in pairs(gridList) do
        repeat
            local summon = grid.summon;

            if not summon then
                -- 没有召唤兽
                break;
            end

            if summon:isDead() then
                -- 召唤兽死亡了
                break;
            end

            -- 刷新属性
            PropM.refreshEffect(summon, "summon_prop");
        until true
    end

    return true;
end

-- 工坊增加的属性
function fetchBlacksmithProp(summon)
    local ret = {};
    local summonId = summon.classId;
    local summonBlacksmith = ME.user.dbase:query("summon_blacksmith", {});
    for _, id in pairs(table.keys(summonBlacksmith)) do
        repeat
            local level = summonBlacksmith[id];
            local bonus = queryBonus(id, "bonus") or {};
            local prop = bonus["prop"];
            if type(prop) ~= "string" or string.len(prop) <= 0 then
                -- 没有增加属性
                break;
            end

            local summonLimit = queryBonus(id, "summon") or {};
            if table.indexOf(summonLimit, summonId) < 0 then
                -- 不是允许的召唤兽
                break;
            end

            -- 属性类统一用公式计算
            local props = FormulaM.invoke(bonus["prop"], id, level);
            ret = table.append(ret, props);
        until true
    end

    return ret;
end

-- 当前等级
function getUpgradeLevel(id)
    local blacksmithInfo = ME.user.dbase:query("summon_blacksmith", {});
    return blacksmithInfo[id] or 0;
end